package com.hospital.config.help;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import common.core.constant.Constant;
import common.core.util.*;
import enhance.plus.logic.LogicBaseServiceImpl;
import enhance.plus.util.LogicDataFill;
import enhance.redis.util.RedisUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.core.ApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数据填充将缓存的数据填充到返回数据中
 *
 * @author 刘波
 */
@Slf4j
@ControllerAdvice
public class DataFillResponseBodyAdvice implements ResponseBodyAdvice {

    private Pattern pattern = Pattern.compile("[\u4e00-\u9fa5]");

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType,
                                  Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (body instanceof Result) {
            Result result = (Result) body;
            Object data = result.getData();
            if (CommonUtil.isNotEmpty(data)) {
                if (data instanceof IPage) {
                    IPage page = (IPage) data;
                    if (CommonUtil.isNotEmpty(page.getRecords())) {
                        List list = page.getRecords();
                        for (Object row : list) {
                            this.initDataFill(row);
                        }
                    }
                } else if (data instanceof Collection) {
                    Collection coll = (Collection) data;
                    for (Object arr : coll) {
                        this.initDataFill(arr);
                    }
                } else if (data.getClass().isArray()) {
                    Object[] array = (Object[]) data;
                    for (Object arr : array) {
                        this.initDataFill(arr);
                    }
                } else {
                    this.initDataFill(data);
                }
            }
            return result;
        } else if (body instanceof Exception) {
            serverHttpResponse.setStatusCode(HttpStatus.OK);
            Exception e = (Exception) body;
            Matcher matcher = pattern.matcher(e.getMessage());
            String message = "系统错误请联系管理员";
            if (matcher.find()) {
                message = e.getMessage();
            }
            return Result.fail(message);
        }
        return body;
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    private <T> void initDataFill(T t) {
        Map<String, Object> map = null;
        if (CommonUtil.isEmpty(t)) {
            return;
        }
        List<Field> fieldList = CommonUtil.getFieldList(t.getClass());
        for (Field field : fieldList) {
            //判断是否是集合类型
            if (Collection.class.isAssignableFrom(field.getType())) {
                //拿到字段值
                try {
                    field.setAccessible(true);
                    Collection collection = (Collection) field.get(t);
                    if (CommonUtil.isEmpty(collection)) {
                        continue;
                    }
                    //遍历集合
                    for (Object o : collection) {
                        //判断集合中的数据是否需要被数据填充--继承了LogicDataFill类
                        if (o instanceof LogicDataFill) {
                            this.initDataFill(o);
                        }
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            DataFill annotation = field.getAnnotation(DataFill.class);
            if (CommonUtil.isNotEmpty(annotation)) {
                if (CommonUtil.isEmpty(map)) {
                    map = CommonUtil.convertBeanToMap(t);
                }
                String entityName = annotation.entityName();
                Class clazz = annotation.clazz();
                if (CommonUtil.isEmpty(clazz) && CommonUtil.isEmpty(entityName)) {
                    log.error("数据填充失败:{}->{}->DataFill->clazz,entityName不能同时为空", t.getClass(), field.getName());
                    throw CustomizeRuntimeException.exception("数据填充失败,请联系管理员");
                }
                String key = CommonUtil.dbForDBToFistLowercaseHump(annotation.field());

                if (CommonUtil.isEmpty(key)) {
                    log.error("数据填充失败:{}->{}->DataFill->key", t.getClass(), field.getName());
                    throw CustomizeRuntimeException.exception("数据填充失败,请联系管理员");
                }
                String value = annotation.value();
                if (CommonUtil.isEmpty(key)) {
                    log.error("数据填充失败:{}->{}->DataFill->value", t.getClass(), field.getName());
                    throw CustomizeRuntimeException.exception("数据填充失败,请联系管理员");
                }

                if (CommonUtil.isEmpty(entityName)) {
                    entityName = clazz.getSimpleName();
                }
                String redisKey = CommonUtil.join(":", Constant.REDIS_ITEM_GENERATE_KEY, entityName, key);
                try {
                    value = CommonUtil.dbForDBToFistLowercaseHump(value);
                    String twoKey = (String) map.get(value);
                    if (CommonUtil.isEmpty(twoKey)) {
                        continue;
                    }
                    log.debug("从redis中拿到数据");
                    Object redisValue = RedisUtil.hget(redisKey, twoKey);
                    if (CommonUtil.isNotEmpty(redisValue)) {
                        field.setAccessible(true);
                        field.set(t, redisValue);
                    } else {
                        log.debug("redis中没有及时同步，从数据库中读取");
                        LogicBaseServiceImpl service = (LogicBaseServiceImpl) SpringUtils.getBean(annotation.serviceName());
                        QueryWrapper queryWrapper = new QueryWrapper();
                        queryWrapper.eq(annotation.field(), twoKey);
                        Object one = service.getOne(queryWrapper);
                        if (CommonUtil.isEmpty(one)) {
                            continue;
                        }
                        Field field1 = one.getClass().getDeclaredField(CommonUtil.dbForDBToFistLowercaseHump(annotation.name()));
                        field1.setAccessible(true);
                        Object dbValue = field1.get(one);
                        if (CommonUtil.isNotEmpty(dbValue)) {
                            field.setAccessible(true);
                            field.set(t, dbValue);
                        }
                        log.debug("将词条数据存入redis");
                        RedisUtil.hset(redisKey,twoKey, dbValue);
                    }
                } catch (Exception e) {
                    log.error("数据填充失败", e);
                    throw CustomizeRuntimeException.exception("数据填充失败,请联系管理员");
                }
            }
        }
    }
}
